/*
 * Copyright (c) 2023-2025 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.util.bean;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/** BeanPath 工具类 - 设置Bean属性值 */
public class BeanAccessor {

  /**
   * 解析Bean中的属性值并设置
   *
   * @param bean Bean对象，支持 Map、List、Collection、Array
   * @param expression 表达式，例如：person.friend[5].name
   * @param value 属性值
   */
  public static void setProperty(Object bean, String expression, Object value) {
    if (bean == null || expression == null || expression.isEmpty()) {
      return;
    }

    String[] tokens = tokenize(expression);
    Object current = bean;

    for (int i = 0; i < tokens.length; i++) {
      String token = tokens[i];
      boolean isLast = i == tokens.length - 1;

      if (current == null) {
        return;
      }

      // Map
      if (current instanceof Map) {
        Map<Object, Object> map = (Map<Object, Object>) current;
        if (isLast) {
          map.put(token, value);
        } else {
          current = map.get(token);
        }
        continue;
      }

      // List or Array
      if (current instanceof List || current.getClass().isArray()) {
        int index;
        try {
          index = Integer.parseInt(token);
        } catch (NumberFormatException e) {
          return;
        }

        if (current instanceof List) {
          List<Object> list = (List<Object>) current;
          if (isLast) {
            list.set(index, value);
          } else {
            current = index >= 0 && index < list.size() ? list.get(index) : null;
          }
        } else {
          int length = Array.getLength(current);
          if (isLast) {
            Array.set(current, index, value);
          } else {
            current = index >= 0 && index < length ? Array.get(current, index) : null;
          }
        }
        continue;
      }

      // Bean
      try {
        Field field = findField(current.getClass(), token);
        if (field == null) {
          return;
        }
        field.setAccessible(true);
        if (isLast) {
          field.set(current, value);
        } else {
          current = field.get(current);
        }
      } catch (IllegalAccessException e) {
        return;
      }
    }
  }

  /** 表达式解析成 token */
  private static String[] tokenize(String expression) {
    expression =
        expression
            .replaceAll("\\['", ".")
            .replaceAll("'\\]", "")
            .replaceAll("\\[", ".")
            .replaceAll("]", "");
    return expression.split("\\.");
  }

  /** 查找字段，包括父类 */
  private static Field findField(Class<?> clazz, String fieldName) {
    while (clazz != null) {
      try {
        return clazz.getDeclaredField(fieldName);
      } catch (NoSuchFieldException e) {
        clazz = clazz.getSuperclass();
      }
    }
    return null;
  }

  /**
   * 解析Bean中的属性值
   *
   * @param <T> 属性值类型
   * @param bean Bean对象，支持 Map、List、Collection、Array
   * @param expression 表达式，例如：person.friend[5].name
   * @return Bean属性值，bean为 {@code null} 或者 expression 为空，返回 {@code null}
   * @since 3.0.7
   */
  @SuppressWarnings("unchecked")
  public static <T> T getProperty(Object bean, String expression) {
    if (bean == null || expression == null || expression.isEmpty()) {
      return null;
    }

    String[] tokens = tokenize(expression);
    Object current = bean;

    for (String token : tokens) {
      if (current == null) {
        return null;
      }

      // Map 获取
      if (current instanceof Map) {
        current = ((Map<?, ?>) current).get(token);
        continue;
      }

      // List / 数组 获取
      if (current instanceof List || current.getClass().isArray()) {
        try {
          int index = Integer.parseInt(token);
          if (current instanceof List) {
            List<?> list = (List<?>) current;
            current = index >= 0 && index < list.size() ? list.get(index) : null;
          } else { // 数组
            int length = Array.getLength(current);
            current = index >= 0 && index < length ? Array.get(current, index) : null;
          }
        } catch (NumberFormatException e) {
          return null;
        }
        continue;
      }

      // Bean 获取
      try {
        Field field = findField(current.getClass(), token);
        if (field == null) {
          return null;
        }
        field.setAccessible(true);
        current = field.get(current);
      } catch (IllegalAccessException e) {
        return null;
      }
    }

    return (T) current;
  }
}
